package organizer.derby;

import java.io.File;
import java.util.List;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import organizer.DepthFirstAlgorithm;
import organizer.Duplicate;
import organizer.FileNodeReader;
import organizer.ICancelable;
import organizer.INodeVisitor;
import organizer.IOrganizerService;
import organizer.IProgressMonitor;
import organizer.NodeVisitorAdapter;

/**
 *
 * @author dawong
 */
public class DerbyOrganizerService implements IOrganizerService {
    
    private static final Logger log = Logger.getLogger(DerbyOrganizerService.class);

    private DerbyOrganizerDao dao;

    public DerbyOrganizerService() {
        DataSource ds = DerbyEnvironment.getDataSource("db");
        dao = new DerbyOrganizerDao(ds);
        log.info("purging cache of obsolete files");
        dao.purge(null);
        report();
    }
    
    public int scanFiles(List<File> sourceDirs, final IProgressMonitor progress) {
        log.info("counting files");
        clearList();
        CounterVisitor counter = new CounterVisitor();
        DepthFirstAlgorithm<File> countAlg = new DepthFirstAlgorithm<File>(new FileNodeReader());
        for (File srcDir : sourceDirs) {
            countAlg.visit(srcDir, counter, progress);
        }
        int count = counter.getCount();
        progress.start(count);
        DepthFirstAlgorithm<File> alg = new DepthFirstAlgorithm<File>(new FileNodeReader());
        log.info("scanning files");
        try {
            for (final File srcDir : sourceDirs) {
                INodeVisitor<File> visitor = new NodeVisitorAdapter<File>() {
                    
                    @Override
                    public void visit(File file) {
                        if (!file.isDirectory()) {
                            if (log.isTraceEnabled())
                                log.trace("adding file: " + file.getAbsolutePath());
                            dao.addFile(srcDir, file);
                            progress.increment(1);
                        }
                    }

                };
                if (progress != null && progress.isCanceled())
                    break;
                alg.visit(srcDir, visitor, progress);
            }
        } catch (Exception e) {
            log.debug(null, e);
        } finally {
            progress.stop();
        }
        return count;
    }
    
    private void clearList() {
        dao.purge(new ICancelable() {

            public boolean isCanceled() {
                return false;
            }
        });
    }

    private static class CounterVisitor extends NodeVisitorAdapter<File> {

        private int count = 0;

        @Override
        public void visit(File node) {
            if (!node.isDirectory()) {
                count++;
            }
        }

        public int getCount() {
            return count;
        }

    }

    public void calcDuplicates(IProgressMonitor progress) {
        log.info("calc duplicates");
        dao.calcDuplicates(progress);
        report();
    }

    public List<Duplicate> getDuplicates(IProgressMonitor progress) {
        log.info("getting duplicates");
        return dao.getDuplicates();
    }
    
    private void report() {
        long allFiles = dao.getFilesInRepositoryCount();
        long scannedFiles = dao.getScannedFilesCount();
        long hashedFiles = dao.getHashedFileCount();
        log.info(hashedFiles + " / " + scannedFiles + " files hashed");
        log.info(allFiles + " in repository");
    }

}
